//
//  MLRefreshAndLazyLoadTableView.m
//  InventoryTool
//
//  Created by molon on 6/5/14.
//  Copyright (c) 2014 Molon. All rights reserved.
//

#import "MLRefreshAndLazyLoadTableView.h"
#import "MLRefreshControl.h"
#import "MolonRequestHelper.h"
#import "UIView+MLKit.h"
#import "UIImage+MLKit.h"
#import "MLKitDefine.h"
#import "Model.h"
#import "ModelArray.h"
#import "MolonAPI.h"

#define kLoadMoreCellHeight 60
#define kRetryButtonTag 111
#define kIndicatorTag 888

//是否需要moreCell和正处于其位置
#define kNeedAndInMoreCell (self.isNeedLazyLoad&&indexPath.row == self.data.count)

@interface MLRefreshAndLazyLoadTableView()


/**
 *  一般是用作在懒加载进程中，有下拉刷新重载请求时候，判断是否是最后发的请求，不是就忽略。
 *  代码中，重载请求比懒加载优先级高。
 */
@property (nonatomic, weak) MolonRequestHelper *lastRequestHelper;

/**
 *  更多cell，懒加载cell，若加载失败显示刷新重试按钮
 */
@property (nonatomic, strong) UITableViewCell *moreCell;

/**
 *  当前页数
 */
@property (nonatomic, assign) NSUInteger currentPageNo;

/**
 *  是否需要懒加载
 *  1.无数据时候不需要懒加载
 *  2.有数据但是未加载完毕时候需要懒加载
 *  3.有数据但已加载完毕时候不需要懒加载
 */
@property (nonatomic, assign) BOOL isNeedLazyLoad;

/**
 *  是否正在请求进行中，重载和懒加载都是请求。
 */
@property (nonatomic, assign) BOOL isLoading;

/**
 *  是否正在重载进程中，用作返回时候和懒加载区分，以做一些重置和结束下拉处理
 */
@property (nonatomic,assign) BOOL isReloading;

@property (nonatomic, strong) ModelArray *data;

@end

@implementation MLRefreshAndLazyLoadTableView

- (void)awakeFromNib
{
    [super awakeFromNib];
    
    //测试发现这个之前会调用initWithCoder,但是initWithCoder设置的值会被重置掉。
    [self setUp];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self setUp];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        //注释掉原因参见awakeFromNib
//        [self setUp];
    }
    return self;
}

- (void)setUp
{
    self.backgroundColor = [UIColor clearColor];
    self.dataSource = self;
    self.delegate = self;
    
//    self.showsVerticalScrollIndicator = NO;
}

#pragma mark - setter
- (void)setLastRequestHelper:(MolonRequestHelper *)lastRequestHelper
{
    if (_lastRequestHelper) {
        [MolonAPI cancelRequestHelper:_lastRequestHelper];
    }
    
    _lastRequestHelper = lastRequestHelper;
}

#pragma mark - getter
- (ModelArray*)data
{
    if (!_data) {
        _data = [[self.modelArrayClass alloc]init];
    }
    return _data;
}

- (Class)modelArrayClass
{
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

#pragma mark - event
- (void)animatingLoadMoreCell:(BOOL)animate
{
    UIButton *retryButton = (UIButton *)[self.moreCell viewWithTag:kRetryButtonTag];
    UIActivityIndicatorView *indicator = (UIActivityIndicatorView *)[self.moreCell viewWithTag:kIndicatorTag];
    
    //转则不可重试，不转则显示重试按钮，点击可重试
    if (animate) {
        retryButton.hidden = YES;
        [indicator startAnimating];
    }else{
        retryButton.hidden = NO;
        [indicator stopAnimating];
    }
}


- (void)retryButtonEvent
{
    [self doSearchForIsNextPage:YES];
}

#pragma mark - data source
//更多cell,默认隐藏重试按钮
- (UITableViewCell*)moreCell
{
    if (_moreCell == nil) {
        static NSString *LoadMoreCellIdentifier = @"LoadMoreCell";
        _moreCell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LoadMoreCellIdentifier];
        
        _moreCell.selectionStyle = UITableViewCellSelectionStyleNone;
        _moreCell.backgroundColor = [UIColor clearColor];
        
        UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
        indicator.center = CGPointMake(self.frameWidth/2, kLoadMoreCellHeight/2);
        indicator.tag = kIndicatorTag;
        [indicator startAnimating];
        [_moreCell addSubview:indicator];
        
        UIButton *retryButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, self.frameWidth, kLoadMoreCellHeight)];
        
        UIImage *refreshImage = [[UIImage imageNamed:MLKIT_BUNDLE_FILE(@"刷新")] imageWithTintColor:[UIColor grayColor]];
        
        [retryButton setImage:refreshImage forState:UIControlStateNormal];
        retryButton.tag = kRetryButtonTag;
        [retryButton addTarget:self action:@selector(retryButtonEvent) forControlEvents:UIControlEventTouchUpInside];
        retryButton.hidden = YES;
        [_moreCell addSubview:retryButton];
    }
    return _moreCell;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    //只能是一个section
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    //需要懒加载则多一行
    return (self.isNeedLazyLoad)?self.data.count+1:self.data.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return kNeedAndInMoreCell?self.moreCell:[self customCellForRow:indexPath.row];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return kNeedAndInMoreCell?kLoadMoreCellHeight:[self customCellHeightForRow:indexPath.row];
}

#pragma mark - delegate
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (!self.isNeedLazyLoad) {
        return;
    }
    
    if (indexPath.row >= (NSInteger)(self.data.count)) {
        //加载下一页
        [self doSearchForIsNextPage:YES];
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (kNeedAndInMoreCell) {
        return;
    }
    
    [self didSelectRow:indexPath.row];
}

#pragma mark - delete delegate
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.isNeedDelete) {
        if (kNeedAndInMoreCell) {
            return NO;
        }
        return YES;
    }
    return NO;
}

//定义编辑样式
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleDelete;
}

//修改编辑按钮文字
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return @"删除";
}

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle==UITableViewCellEditingStyleDelete) {
        
    }  
}

#pragma mark - out call
- (void)validatePullDownToRefresh
{
    //给自己添加下下拉刷新
    WEAKSELF
    [self enableRefreshingWithAction:^{
        STRONGSELF
        [sSelf doReload];
    } scrollToTopAfterEndRefreshing:YES];
}

- (void)doReload
{
    [self doSearchForIsNextPage:NO];
}

- (void)clearAndResetData
{
    self.lastRequestHelper = nil;
    [self endRefreshing];
    
    self.currentPageNo = 0;
    self.isNeedLazyLoad = NO;
    self.isReloading = NO;
    self.isLoading = NO;
    
    [self.data removeAllObjects];
    [self reloadData];
}

- (void)doneSearchWithRequestHelper:(MolonRequestHelper*)requestHelper andResult:(ModelArray*)result andIsSuccess:(BOOL)isSuccess andIsLoadedAll:(BOOL)isLoadedAll
{
    if (self.lastRequestHelper&&![requestHelper isEqual:self.lastRequestHelper]) {
        return; //不是最后投递的请求就直接忽略
    }
    
    self.isLoading = NO;
    
    if (self.isReloading) {
        [self endRefreshing];
    }
    
    if (isSuccess) {
        if (self.isReloading) {
            self.isReloading = NO;
            [self clearAndResetData];
        }
        
        if (!isLoadedAll){
            self.isNeedLazyLoad = YES;
        }
        //检查结果是否是空的
        if (result.count<=0&&!isLoadedAll) { //如果由于去重完毕之后变成0，实际上不能认为loadedAll，所以这里重新请求这一页数据
            self.currentPageNo++; //这里说明这一页和上面的完全重复，加一页吧，防止会死循环。中间如果丢数据了也没辙了。page分页就是如此
            [self doSearchForIsNextPage:YES];
            return;
        }
        
        if (isLoadedAll) {
            //为空或者明确表示没了，说明真的没了，就删除了更多cell行吧
            self.isNeedLazyLoad = NO;
            if ([self numberOfRowsInSection:0]>self.data.count) {
                [self deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.data.count inSection:0]] withRowAnimation:UITableViewRowAnimationAutomatic];
#warning when result==0 tableview bounces  的时候这里动画结束会很僵硬的回弹，不知是不是下拉刷新的影响，实在不行回头仿照聊天那个处理
            }
        }
        
        if (result.count>0) {
            self.currentPageNo++;
            
            NSMutableArray *indexes = [NSMutableArray array];
            
            for (NSUInteger i=0; i<result.count; i++) {
                [indexes addObject:[NSIndexPath indexPathForRow:self.data.count+i inSection:0]];
            }
            
            //添加到data里
            [self.data addObjectsFromArray:result.array];
            
            //添加到界面
            if (self.currentPageNo==1) {
                [self reloadData];
            }else{
                [CATransaction setDisableActions:YES];
                [self insertRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationNone];
                [CATransaction setDisableActions:NO];
            }
            if (self.isNeedLazyLoad) {
                NSArray *visibleIndexPaths = [self indexPathsForVisibleRows];
                if ([visibleIndexPaths containsObject:[NSIndexPath indexPathForRow:self.data.count inSection:0]]) {
                    //在这里是有可能出现插入上面的新数据后，懒加载行已经显示了，那这时候，willDisplay就不会触发。所以这里我们检测下，检测到了就主动触发下。
                    [self doSearchForIsNextPage:YES];
                }
            }
        }
    }else{
        if (self.isReloading) {
            self.isReloading = NO;//失败了就只能重新来了
            
            
            //这里可能会发生这样的情况，重载失败，然后由于之前的数据未消除。
            //重载条件可能已经发生变化，然后之后懒加载重新可用，所以懒加载出来的数据和之前的数据可能不是一个条件下的。
            //这里只能要求告诉外部，让其做回归条件处理
            [self reloadFailed];
        }else{
            //显示重试懒加载按钮
            [self animatingLoadMoreCell:NO];
        }
    }
}


#pragma mark - request
- (void)doSearchForIsNextPage:(BOOL)isNextPage
{
    if (!isNextPage) {
        //判断当前是否有数据，无的话就不需要懒加载
        if (self.data.count<=0) {
            self.isNeedLazyLoad = NO;
        }
        
        //reload
        self.isReloading = YES;
        
        //直接设置isLoading是因为无需等待上次请求的结束，在回调里会对lastPostHelper进行验证，如果不是最后投递的请求，就直接忽略。
        self.isLoading = YES;
        
        //获取内容
        MolonRequestHelper *helper = [self requestHelperForIsNextPage_Parent:NO];
        
        self.lastRequestHelper = helper; //设置最后投递时间
        
        [MolonAPI requestWithHelper:helper andBindObject:self];
    }else{
        if (!self.isLoading) {
            self.isLoading = YES;
            
            //获取内容
            MolonRequestHelper *helper = [self requestHelperForIsNextPage_Parent:YES];
            
            self.lastRequestHelper = helper; //设置最后投递时间
            
            [MolonAPI requestWithHelper:helper andBindObject:self];
            
            [self animatingLoadMoreCell:YES];
        }
    }
}


#pragma mark - inherit 留作继承的
- (void)setCustomRequestHelperBlock:(MolonRequestHelper *(^)(MLRefreshAndLazyLoadTableView *tableView,BOOL isNextPage))block
{
    _customRequestHelperBlock = [block copy];
}

- (MolonRequestHelper*)requestHelperForIsNextPage_Parent:(BOOL)isNextPage
{
    if (self.customRequestHelperBlock) {
        return self.customRequestHelperBlock(self,isNextPage);
    }
    return [self requestHelperForIsNextPage:isNextPage];
}

- (MolonRequestHelper*)requestHelperForIsNextPage:(BOOL)isNextPage
{
    return nil;
}

- (UITableViewCell*)customCellForRow:(NSUInteger)row
{
    return nil;
}

- (CGFloat)customCellHeightForRow:(NSUInteger)row
{
    return 0;
}

- (void)didSelectRow:(NSUInteger)row
{
    
}

- (void)reloadFailed
{
    
}
@end
